//
// Created by luo on 2022-09-01.
//
#include "../opencv/OpenCv.h"

/*
 * 图像采集设备受光子、电子等干扰，或者图像传输中产生噪声
 * 使用线性/非线性滤波，处理噪声或者求取边缘信息
 * */

/*
 * 确定一个尺寸比待卷积的原始图小的卷积图(固定大小的二维矩阵),称为卷积模板，
 * 要首先对其进行180°的旋转,使其不断从左到右上到下移动
 * 对每个覆盖区域进行点乘(对应位置像素相乘然后求和)，得到的值作为中心像素点的输出值。
 * */

/*
 * 由于卷积模板中心不能放在图像边缘，因此通常将卷积模板缩放使得所有数值的和为1，防止越界
 * */
void QuickDemo::my_filter2D(Mat &mat)//图像卷积
{
    /*
     * 图像和卷积模板的卷积运算
     * filter2D(src,dst,ddepth,kernel,anchor,delta,borderType)
     * 输入图，输出图，输出图像的数据类型(深度，根据输入图像数据类型而定,-1为自动选择)
     * 卷积核(CV_32FC1,奇数模板 3*3 5*5等)
     * 内核基准点(默认(-1,-1,)位于中心位置)，偏值，像素外推法选择标志
     * */
    //待卷积矩阵
    uchar points[25] = {};
    auto i = 1;
    for(size_t t = 0; t < 25; t++)
    {
        points[t] = i;
        if(++i == 26) i = 25;
    }
    //cout<<"i "<<i<<" points "<<points[24]<<endl;
    cv::Mat img(5,5,CV_8UC1,points);
    //卷积模板
    cv::Mat kernel = (Mat_<float>(3,3)<<1,2,1,
            2,0,2,
            1,2,1);
    //卷积模板归一化
    cv::Mat kernel_normal = kernel/12;
    //未归一化与归一化卷积的结果
    cv::Mat result,result_normal;
    //卷积操作
    cv::filter2D(img,result,-1,kernel,Point(-1,-1),2,BORDER_CONSTANT);
    cv::filter2D(img,result_normal,-1,kernel_normal,Point(-1,-1),2,BORDER_CONSTANT);
    std::cout<<"result: "<<std::endl<<result<<std::endl;
    std::cout<<"result_normal: "<<std::endl<<result_normal<<std::endl;
    //相同卷积模板对彩色图像进行卷积，有模糊作用
    cv::Mat lena_filter;
    cv::filter2D(mat,lena_filter,-1,kernel_normal,Point(-1,-1),2,BORDER_CONSTANT);
    cv::namedWindow("mat",WINDOW_NORMAL);
    cv::imshow("mat",mat);
    //图像滤波处理后，整体图像亮度变高，模糊度变高，黑斑变少
    cv::namedWindow("lena_filter",WINDOW_NORMAL);
    cv::imshow("lena_filter",lena_filter);
    cv::waitKey(0);
    cv::destroyAllWindows();
}

/*
 * 光电引起的噪声妨碍图像处理理解和应用，分别有高斯噪声，椒盐噪声，泊松噪声和乘性噪声等等
 * 椒盐噪声(脉冲噪声)，随机改变图像中的像素值，样子就像是图像中随机撒上盐粒和黑椒粒
 * 用户需要自己使用算法产生椒盐噪声
 * */

void saltPepper_deal(cv::Mat img,int n)
{
    for(auto k = 0; k < n/2; k++)
    {
        //随机确定图像的位置
        int i, j;
        i = cvflann::rand()%img.cols;
        j = cvflann::rand()%img.rows;
        auto write_or_black = cvflann::rand() %2;//判断黑白
        if(write_or_black == 0)
        {
            //白色噪声
            if(img.type() == CV_8UC1)//灰度图
            {
                img.at<uchar>(j,i) = 255; //白色
            }
            else if(img.type() == CV_8UC3)
            {
                img.at<Vec3b>(j,i)[0] = 255; //B
                img.at<Vec3b>(j,i)[1] = 255; //G
                img.at<Vec3b>(j,i)[2] = 255; //R
            }
        }
        else //黑色噪声
        {
            //白色噪声
            if(img.type() == CV_8UC1)//灰度图
            {
                img.at<uchar>(j,i) = 0; //白色
            }
            else if(img.type() == CV_8UC3)
            {
                img.at<Vec3b>(j,i)[0] = 0; //B
                img.at<Vec3b>(j,i)[1] = 0; //G
                img.at<Vec3b>(j,i)[2] = 0; //R
            }
        }
    }
}

void QuickDemo::my_jyvoice(Mat &mat)//椒盐噪声
{
    /*
     * 产生随机数的函数
     * int cvflann::rand()
     * double cvflann::rand_double(double high = 1.0,double low = 0)
     * int cvflann::rand_int(int high = RAND_MAX,int low = 0)
     * high为输出随机数最大值，low为输出随机数最小值
     *
     * 生成0-100的整数，可以 int a = rand()%100
     * */

    /*
     * 步骤: 1、确定添加椒盐噪声的位置(随机数 行 列)
     *      2、确定噪声的种类(噪声点是黑、白、还是随机)
     *      3、修改图像像素的灰度值(判断图像通道数)
     *      4、得到含有椒盐噪声的图像
     * */
    cv::Mat gray;
    cv::cvtColor(mat,gray,COLOR_BGR2GRAY);
    cv::imshow("gray",gray);
    saltPepper_deal(mat,10000);
    saltPepper_deal(gray,10000);
    imshow("mat salt",mat);
    imshow("gray salt",gray);
    imwrite("C:\\Pictures\\15.jpg",gray);
    cv::waitKey(0);

}

/*
 * 高斯噪声，噪声分布的概率密度函数服从高斯(正态)分布，主原因是相机拍摄时现场较暗且亮度不均匀
 * 椒盐噪声随机出现在图像中任意位置，高斯噪声则出现在图像中所有位置
 * fill()函数产生均匀分布或者高斯分布的随机数
 * */

void QuickDemo::my_gaussvoice(Mat &mat)//高斯噪声
{
    /*
     * 利用该函数产生符合高斯分布的随机数，然后在图像中加入它们
     * void cv::RNG::fill(mat,disType,a,b,saturateRange);
     * 存放随机数的矩阵，随机分布标志(RNG::UNIFORM,RNG::NORMAL)
     * 确定分布规律参数(均匀时，最小下限和最大上限；高斯时，均值和标准差)
     * 预饱和标志，仅用于均匀分布
     *
     * fill()调用方式
     * cv::RNG rng;
     * rng.fill(mat,RNG::NORMAL,10,20);
     * */

    /*
     * 图像中添加高斯噪声步骤
     * 一、创建一个类型与尺寸(通道数)相同的Mat类变量
     * 二、调用fill()在Mat中产生高斯分布的随机数
     * 三、将原始图与含有高斯分布的随机数矩阵相加
     * 四、得到高斯噪声图
     * */
    cv::Mat gray;
    cv::cvtColor(mat,gray, COLOR_BGR2GRAY);
    //生成相同图
    cv::Mat mat_noise = cv::Mat::zeros(mat.rows,mat.cols,mat.type());
    cv::Mat gray_noise = cv::Mat::zeros(gray.rows,gray.cols,gray.type());
    //创建RNG类
    cv::RNG rng;
    //生成三/单通道高斯分布随机数
    rng.fill(mat_noise,RNG::NORMAL,10,20);
    rng.fill(gray_noise,RNG::NORMAL,15,30);
    cv::imshow("mat_noise",mat_noise);
    cv::imshow("gray_noise",gray_noise);

    //在彩/灰色图像中添加高斯噪声
    mat+=mat_noise;
    gray+=gray_noise;
    //显示高斯噪声图
    cv::imshow("after mat_noise",mat);
    cv::imshow("after gray_noise",gray);
    imwrite("C:\\Pictures\\14.jpg",gray);
    cv::waitKey(0);

}


/*
 * 线性滤波
 * 在均值滤波中 将滤波器中所有的像素值求和后的平均值作为滤波后结果
 * */
void QuickDemo::my_linearfiltering_average(Mat &mat)
{
    /*
     * void cv::blur(src,dst,ksize,anchor,borderType);
     * 待均值滤波的图像，均值滤波后的图像，卷积核尺寸(奇数尺寸)，内核基准点(-1,-1)，像素外推标志
     * 滤波器尺寸越大，滤波图像越模糊，平滑，看上去噪声效果越少
     * */
    cv::Mat img_g = imread("C:\\Pictures\\14.jpg");
    cv::Mat img_j = imread("C:\\Pictures\\15.jpg");
    if (img_g.empty() || img_j.empty()) {
        cout << "Error" << endl;
        return ;
    }
    cv::Mat result_3,result_9; //存放不含噪声滤波,数字代表滤波器尺寸
    cv::Mat result_3gauss,result_9gauss; //存放含有高斯噪声滤波
    cv::Mat result_3salt,result_9salt;  //存放含有椒盐噪声滤波
    //调用均值滤波函数blur()
    cv::blur(mat,result_3,Size(3,3));
    cv::blur(mat,result_9,Size(9,9));
    cv::blur(img_g,result_3gauss,Size(3,3));
    cv::blur(img_g,result_9gauss,Size(9,9));
    cv::blur(img_j,result_3salt,Size(3,3));
    cv::blur(img_j,result_9salt,Size(9,9));
    //显示不含噪声图
    cv::imshow("mat",mat);
    cv::imshow("result_3",result_3);
    cv::imshow("result_9",result_9);
    //显示含有高斯噪声图像
    cv::imshow("img_g",img_g);
    cv::imshow("result_3gauss",result_3gauss);
    cv::imshow("result_9gauss",result_9gauss);
    //显示含有椒盐噪声图像
    cv::imshow("img_j",img_j);
    cv::imshow("result_3salt",result_3salt);
    cv::imshow("result_9salt",result_9salt);
    cv::waitKey(0);
}

/*
 * 方框滤波
 * 方框滤波也是求滤波器内所有像索值的和 ，但是方框滤波可以选择不进行归一化
 * 是将所有像素值的和作为滤波结果，而不是所有像素值的平均值.
 * */
void QuickDemo::my_linearfiltering_rect(Mat &mat)
{
    /*
     * void boxFilter(src,dst,ddepth,ksize,anchor,normalize,boderType)
     * 输入图，输出图，输出图像的深度(数据类型，-1为自动选择)，卷积核尺寸
     * 内核的基准点(锚点，默认值为(-1,-1))，是否将卷积核归一化标志(默认为true)，像素边界外推
     * */

    /*
     * 对滤波器内每个像素值的平方求和，之后根据输入参数选择是否进行归一化操作
     * void sqrBoxFilter(src,dst,ddepth,ksize,anchor,normalize,boderType)
     * 该函数主要针对CV_32F数据类型图像，且在归一化后，图像在变模糊的同时亮度也会变暗
     * */
    cv::Mat gray;
    cv::cvtColor(mat,gray,COLOR_BGR2GRAY);
    //验证方框滤波算法数据矩阵
    float points[25] = {};
    float i = 1;
    for(size_t t = 0; t < 25; t++)
    {
        points[t] = i;
        if(++i == 26) i = 25;
    }
    cv::Mat data(5,5,CV_32FC1,points);
    //CV_8U -> CV_32F
    cv::Mat equalLena_32F;
    gray.convertTo(equalLena_32F,CV_32F,1.0/255);
    cv::Mat resultNorm,result,dataSqrNorm,dataSqr,enquallena_32FSqr;
    //方框滤波函数
    cv::boxFilter(gray,resultNorm,-1,Size(3,3),Point(-1,-1),true);//归一化
    cv::boxFilter(gray,result,-1,Size(3,3),Point(-1,-1),false);//不归一化
    cv::sqrBoxFilter(data,dataSqrNorm,-1,Size(3,3),Point(-1,-1),true,BORDER_CONSTANT);//进行归一化
    cv::sqrBoxFilter(data,dataSqr,-1,Size(3,3),Point(-1,-1),false,BORDER_CONSTANT);//不进行归一化
    cv::sqrBoxFilter(equalLena_32F,enquallena_32FSqr,-1,Size(3,3),Point(-1,-1),true,BORDER_CONSTANT);//不进行归一化
    //显示结果
    cv::imshow("resultNorm",resultNorm);
    cv::imshow("result",result);
    cv::imshow("enquallena_32FSqr",enquallena_32FSqr);
    cv::waitKey(0);
}

/*
 * 高斯滤波，为解决图像采集中引入的高斯噪声而生。
 * 像素离滤波器中心距离的影响，以滤波器中心距离为高斯分布的均值
 * 由高斯分布公式和每个像素中心位置的距离计算出滤波器内每个位置的数值
 * */
void QuickDemo::my_linearfiltering_gauss(Mat &mat)
{
    /*
     * 高斯滤波
     * void GaussianBlur(src，dst，ksize，sigmaX，sigmaY，borderType);
     * 输入图，输出图，高斯滤波器尺寸(必须为正奇数，为0按标志偏差计算尺寸)
     * X方向标准偏差，Y方向标准偏差(为0,则为sigmaX，X也为0，则按标准)，像素边界外推
     * */

    /*
     * 生成单一方向高斯滤波器
     * void getGaussianKernel(ksize,sigma,ktype)
     * 高斯滤波器尺寸(必须是一个正奇数)，标准差，系数的数据类型(CV_32F/CV_64F，默认后者)
     * 该函数生成一个ksize*1的Mat类矩阵
     * */

    //高斯滤波对高斯噪声去除效果较好，但同样会对图像造成模糊，且滤波器尺寸越大，滤波后的图像变得越模糊
    cv::Mat img_g = imread("C:\\Pictures\\14.jpg");
    cv::Mat img_j = imread("C:\\Pictures\\15.jpg");
    if (img_g.empty() || img_j.empty()) {
        cout << "Error" << endl;
        return ;
    }
    cv::Mat result_5,result_9;
    cv::Mat result_5gauss,result_9gauss;
    cv::Mat result_5salt,result_9salt;
    //高斯滤波函数进行滤波
    Size kernel_5 = Size(5,5);
    Size kernel_9 = Size(9,9);
    GaussianBlur(mat,result_5,kernel_5,10,20);
    GaussianBlur(mat,result_9,kernel_9,10,20);
    GaussianBlur(img_g,result_5gauss,kernel_5,10,20);
    GaussianBlur(img_g,result_9gauss,kernel_9,10,20);
    GaussianBlur(img_j,result_5salt,kernel_5,10,20);
    GaussianBlur(img_j,result_9salt,kernel_9,10,20);
    //显示不含噪声图像
    cv::imshow("mat",mat);
    cv::imshow("result_5",result_5);
    cv::imshow("result_9",result_9);
    //含有高斯噪声
    cv::imshow("img_g",img_g);
    cv::imshow("result_5gauss",result_5gauss);
    cv::imshow("result_9gauss",result_9gauss);
    //含有椒盐噪声
    cv::imshow("img_j",img_j);
    cv::imshow("result_5salt",result_5salt);
    cv::imshow("result_9salt",result_9salt);
    cv::waitKey(0);
}

/*
 * 可分离滤波
 * 实际应用中需要根据需求调整滤波模板，例如滤波器中心位置像素值不计算，或者参与计算值不是矩形区域
 * 自适应滤波器，卷积函数filter2D(),输出的卷积模板称为滤波器或滤波模板
 * 图像滤波是并行算法，且有可分离性(先对X（Y）方向滤波，再对Y(X)方向滤波的结果与两个方向滤波器联合后整体滤波结果相同)
 * 联合就是两个方向滤波器相乘得到矩形滤波器
 * 两个方向联合滤波需要filter2D()之前计算联合滤波器，两个方向分别滤波要调用两次filter2D()，因此有sepFilter2D（）
 * */
void QuickDemo::my_linearfiltering_split(Mat &mat)
{
    /* 输入两个方向滤波器实现滤波,可分离线型滤波器分成X方向和Y方向处理
     * sepFilter2D(src,dst,ddepth,kernelX,kernelY,anchor,delta,boderType)
     * 输入图，输出图，输出图深度，X/Y方向滤波器，内核锚点，偏值，边界外推标志
     * */
    system("color F0");
    float points[25] = {1,2,3,4,5,
                        6,7,8,9,10,
                        11,12,13,14,15,
                        16,17,18,19,20,
                        21,22,23,24,25};
    cv::Mat data(5,5,CV_32FC1,points);
    //X,Y方向和联合滤波器的构建
    cv::Mat a = (cv::Mat_<float>(3,1)<<-1,3,-1);
    cv::Mat b = a.reshape(1,1);
    cv::Mat ab = a*b;
    //验证高斯滤波器的可分离性
    //生成单一方向的高斯滤波器
    cv::Mat gaussX = getGaussianKernel(3,1);
    cv::Mat gaussData,gaussDataXY;
    cv::GaussianBlur(data,gaussData,Size(3,3),1,1,BORDER_CONSTANT);
    cv::sepFilter2D(data,gaussDataXY,-1,gaussX,gaussX,Point(-1,-1),0,BORDER_CONSTANT);
    //输入两种高斯滤波的计算结果
    std::cout<<"gaussData="<<std::endl<<gaussData<<std::endl;
    std::cout<<"gaussDataXY="<<std::endl<<gaussDataXY<<std::endl;
    //线性滤波的可分离性
    cv::Mat dataYX,dataY,dataXY,dataXY_sep;
    Point base_point = Point(-1,-1);
    cv::filter2D(data,dataY,-1,a,base_point,0,BORDER_CONSTANT);
    cv::filter2D(dataY,dataYX,-1,b,base_point,0,BORDER_CONSTANT);
    cv::filter2D(data,dataXY,-1,ab,base_point,0,BORDER_CONSTANT);
    cv::sepFilter2D(data,dataXY_sep,-1,b,b,base_point,0,BORDER_CONSTANT);
    //输入可分离滤波和联合滤波的计算结果
    std::cout<<"dataY="<<std::endl<<dataY<<std::endl;
    //证明并行与可分离原理
    std::cout<<"dataYX="<<std::endl<<dataYX<<std::endl;
    std::cout<<"dataXY="<<std::endl<<dataXY<<std::endl;
    std::cout<<"dataXY_sep="<<std::endl<<dataXY_sep<<std::endl;
    //对图像分离
    cv::Mat imgYX,imgY,imgXY;
    cv::filter2D(mat,imgY,-1,a,base_point,0,BORDER_CONSTANT);
    cv::filter2D(mat,imgYX,-1,b,base_point,0,BORDER_CONSTANT);
    cv::filter2D(mat,imgXY,-1,ab,base_point,0,BORDER_CONSTANT);
    cv::imshow("imgYX",imgYX);
    cv::imshow("imgY",imgY);
    cv::imshow("imgXY",imgXY);
    cv::waitKey(0);
}

/*
 * 非线性滤波，滤波器内像素值通过非线性计算得出，可能包含排序、逻辑运算等
 * 非线性滤波可以通过逻辑判断，去除线性滤波不能处理的噪声。
 * 常见：中值滤波和双边滤波
 * */

/*
 * 中值滤波，用滤波器范围内所有像素值的中值来替代滤波器中心位置像素值
 * 将滤波器范围内所有的像素值按照自小到大的顺序排列 选取排序序列的中值作为滤波器中
    心处阴影像素的新像素值,之后将滤波器移动到下一个位置,重复进行排序取中值的操作,直到将
    图像所有像素点都被滤波器中心对应一遍。
 * 对斑点噪声和椒盐噪声的处理具有较好的效果。
 * 对于均值滤波，对脉冲干扰和图像扫描噪声处理更佳，对图像边缘信息保护效果更佳，避免图像细节模糊(size变大后同样有)
 * 且处理时间远大于均值滤波
 * */
void QuickDemo::my_notlinearfiltering_medianBlur(Mat &mat)//中值滤波
{
    /*
     * void medianBlur(src,dst,ksize);
     * 待中值滤波图，输出图像，滤波器尺寸(必须是大于一的奇数)
     * */
    cv::Mat img_g = imread("C:\\Pictures\\14.jpg");
    cv::Mat img_j = imread("C:\\Pictures\\15.jpg");
    if (img_g.empty() || img_j.empty()) {
        cout << "Error" << endl;
        return ;
    }
    cv::Mat imgResult_3,grayResult_3,imgResult_9,grayResult_9;
    //分别对含有椒盐噪声的彩色图和灰度图进行滤波,3*3
    cv::medianBlur(img_j,imgResult_3,3);
    cv::medianBlur(img_g,grayResult_3,3);
    //9*9，图像滤波结果更模糊
    cv::medianBlur(img_j,imgResult_9,9);
    cv::medianBlur(img_g,grayResult_9,9);

    //显示滤波处理结果
    cv::imshow("img_j",img_j);
    cv::imshow("img_g",img_g);
    cv::imshow("imgResult_3",imgResult_3);
    cv::imshow("grayResult_3",grayResult_3);
    cv::imshow("imgResult_9",imgResult_9);
    cv::imshow("grayResult_9",grayResult_9);
    cv::waitKey(0);

}

/*
 * 双边滤波,综合考虑滤波器内图像空域信息和滤波器内图像像素灰度值相似性，
 * 可以实现在保留图像边缘信息的基础上实现对噪声去除、对局部边缘的平滑。
 * 对高频率的波动信号有平滑作用，保留大幅度变化的信号波动
 * */
void QuickDemo::my_notlinearfiltering_bilateralFilter(Mat &mat)//双边滤波
{
    /*
     * 双边滤波
     * void bilateralFilter(src,dst,d,sigmaColor,sigmaSpace,borderType);
     * 待滤波图(CV_8U/32F/64F,单/三通道),输出图，每个像素邻域直径(<0由第五个参数计算)
     * 颜色空间滤被器的标准差值(越大，像素领域内越多颜色混合一起，产生较大的半相等颜色区域)
     * 空间坐标中滤波器的标准差值(越大，越远的像素会相互影响，更大领域中有足够相似的颜色获取相同颜色)
     * sigmaColor 和 sigmaSpace 可设置成相同值 <10 滤波效果较弱 >150 滤波效果非常强烈
     * */

    /*
     * 滤波器的直径对于滤波效果具有重要的影响 滤波器直径越大，滤波效果越明显.
     * 当滤波器直径相同时，标准差值越大，滤波效果越明显
     * */
    cv::Mat result1,result2,result3,result4;
    //不同滤波器直径滤波效果
    cv::bilateralFilter(mat,result1,9,50,25/2);
    cv::bilateralFilter(mat,result2,25,50,25/2);
    //不同标准差值滤波效果
    cv::bilateralFilter(mat,result3,9,9,9);
    cv::bilateralFilter(mat,result4,9,200,200);

    //显示原图
    cv::imshow("mat",mat);
    //不同直径
    cv::imshow("result1",result1);
    cv::imshow("result2",result2);
    //不同标准差
    cv::imshow("result3",result3);
    cv::imshow("result4",result4);
    cv::waitKey(0);

}

/*
 * 边缘检测，提取图像边缘信息，实现物体分割、定位
 * 边缘指的是图像中像素灰度值突然发生变化的区域
 * 原理:灰度值函数思想(把每一行/列像素关系描述成f(x))，当函数值突然变大，导数值必然变大
 * 而函数变化较为平缓的地方，导数值也较小，因此可以通过寻找导数值大小来进行判断，进而确定图像边缘区域
 * 由图像离散信号特性，像素灰度值f'(x) = 临近两个(x+1 与 x-1)像素差值
 * 表达式为正，像素值由低变高，反之。二者都是图像边缘区域，因此求绝对值
 * */
void QuickDemo::my_edgedetection_converAbs(Mat &mat)//图像边缘检测原理
{
    /*
     * 计算矩阵中所有数据的绝对值
     * void convertScaleAbs(src,dst,alpha,beta);
     * 输入矩阵，输出矩阵，缩放因子(默认不缩放),偏值(默认不添加)
     * */

    //利用filter2D()实现图像边缘检测算法
    //创建边缘检测滤波器
    cv::Mat kernel1 = (cv::Mat_<float>(1,2)<<1,-1);//X
    cv::Mat kernel2 = (cv::Mat_<float>(1,3)<<1,0,-1);//X
    cv::Mat kernel3 = (cv::Mat_<float>(3,1)<<1,0,-1);//X
    cv::Mat kernelXY = (cv::Mat_<float>(2,2)<<1,0,0,-1);//左上到右下
    cv::Mat kernelYX = (cv::Mat_<float>(2,2)<<0,-1,1,0);//右上到左下

    cv::Mat result1,result2,result3,result4,result5,result6;

    //检测图像边缘
    //[1 -1] 检测水平方向边缘
    //求取边缘结果可能有负数，滤波后数据类型要CV_16S
    cv::filter2D(mat,result1,CV_16S,kernel1);
    cv::convertScaleAbs(result1,result1);
    //[1 0 -1] 检测水平方向边缘
    //求取边缘结果可能有负数，滤波后数据类型要CV_16S
    cv::filter2D(mat,result2,CV_16S,kernel2);
    cv::convertScaleAbs(result2,result2);
    //[1 0 -1] 检测垂直方向边缘
    //求取边缘结果可能有负数，滤波后数据类型要CV_16S
    cv::filter2D(mat,result3,CV_16S,kernel3);
    cv::convertScaleAbs(result3,result3);
    //检测整幅图像边缘
    //求取边缘结果可能有负数，滤波后数据类型要CV_16S
    result6 = result2 + result3;
    //左上到右下边缘
    cv::filter2D(mat,result4,CV_16S,kernelXY);
    cv::convertScaleAbs(result4,result4);
    //右上到左下边缘
    cv::filter2D(mat,result5,CV_16S,kernelYX);
    cv::convertScaleAbs(result5,result5);
    cv::imshow("result1",result1);
    cv::imshow("result2",result2);
    cv::imshow("result3",result3);
    cv::imshow("result4",result4);
    cv::imshow("result5",result5);
    cv::imshow("result6",result6);
    cv::waitKey(0);

}

void QuickDemo::my_edgedetection_Sobel(Mat &mat)
{

}

void QuickDemo::my_edgedetection_Scharr(Mat &mat)
{

}

void QuickDemo::my_edgedetection_DerivKernels(Mat &mat)
{

}

void QuickDemo::my_edgedetection_Laplacian(Mat &mat)
{

}

/*
 * Canny算法不容易受到噪声影响，能识别图像中的弱边缘与强边缘，
 * 并结合强弱边缘的位置关系，综合给出图像整体边缘信息
 * */

/*
 * 步骤:一、使用高斯滤波平滑图像，减少噪声(5*5高斯滤波器)
 *     二、计算图像中每个像素的梯度方向和幅值，先用Sobel算子分别检测X,Y方向边缘，然后公式计算
 *     三、应用非极大值抑制算法消除边缘检测带来的杂散响应(梯度强度比较，当前最大则保留为边缘点，否则抑制)
 *     四、应用双阑值法划分强边缘和弱边缘
 *     五、消除孤立的弱边缘
 * */
void QuickDemo::my_edgedetection_Canny(Mat &mat)
{
    /*
     * 实现 Canny算法检测图像中的边缘
     * void canny(src,dst,threshold1,threshold2,apertureSize,L2gradient)
     * 输入图，输出图，第一/二个滞后阈值，Sobel算子直径，计算图像梯度幅值方法标志.
     * */

    //较高的阙值会降低噪声信息对图像提取边缘结果的影响 但是同时也会减少结果中的边缘信息.
    cv::Mat resultHigh,resultLow,resultG;
    //高阈值
    cv::Canny(mat,resultHigh,100,200,3);
    //低阈值
    cv::Canny(mat,resultLow,20,40,3);

    //高斯模糊后检测图像边缘
    cv::GaussianBlur(mat,resultG,Size(3,3),5);
    cv::Canny(resultG,resultG,100,200,3);
    cv::imshow("resultHigh",resultHigh);
    cv::imshow("resultLow",resultLow);
    cv::imshow("resultG",resultG);
    cv::waitKey(0);

}
